package cuppics;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class Prj67 {

	/**
	 * By starting at the top of the triangle below and moving to adjacent
	 * numbers on the row below, the maximum total from top to bottom is 23.
	 * 
	 * 3 7 4 2 4 6 8 5 9 3
	 * 
	 * That is, 3 + 7 + 4 + 9 = 23.
	 * 
	 * Find the maximum total from top to bottom of the triangle below:
	 * 
	 * 75 95 64 17 47 82 18 35 87 10 20 04 82 47 65 19 01 23 75 03 34 88 02 77
	 * 73 07 63 67 99 65 04 28 06 16 70 92 41 41 26 56 83 40 80 70 33 41 48 72
	 * 33 47 32 37 16 94 29 53 71 44 65 25 43 91 52 97 51 14 70 11 33 28 77 73
	 * 17 78 39 68 17 57 91 71 52 38 17 14 91 43 58 50 27 29 48 63 66 04 68 89
	 * 53 67 30 73 16 69 87 40 31 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
	 * @throws IOException 
	 */
	@Test
	public void test() throws IOException {
		List<int[]> dataList = Calculator.readData("D:\\workSpace\\java\\cuppics\\src\\test\\java\\cuppics\\Prj67_data.txt"); 
		Calculator.calculate(dataList, 100);
	}

	public static class Calculator {

		public enum Direction {
			Down, DownLeft, DownRight
		}
		
		public static String directionStr( Direction dir){
			if( dir.equals( Direction.Down)){
				return "↓";
			}else if ( dir.equals( Direction.DownLeft)){
				return "↙";
			}else if( dir.equals( Direction.DownRight)){
				return "↘";
			}
			
			return "==";
		}

		public static List<int[]> readData(String path) throws IOException {

			BufferedReader reader = new BufferedReader(new InputStreamReader(
					new FileInputStream(new File(path))));

			String str = null;
			List<int[]> ret = new ArrayList<int[]>();
			while ((str = reader.readLine()) != null) {
				String[] dataStr = str.split(" ");
				int[] data = new int[dataStr.length];
				for (int i = 0; i < dataStr.length; i++) {
					data[i] = Integer.parseInt(dataStr[i]);
				}
				ret.add(data);
			}
			reader.close();
			return ret;

		}

		public static void calculate(List<int[]> dataList, int lastDataLen) {

			String[] traceStr = new String[lastDataLen];
			String[] traceStrCopy = new String[lastDataLen];
			
			
			int [] maxSumCopy = new int[ lastDataLen];
			int [] maxSum = new int[ lastDataLen];
			
			for (int i = 0; i < traceStr.length; i++) {
				traceStr[i] = "";
				traceStrCopy[i] = "";
				maxSum[0] = dataList.get(0)[0];
			}
						
			for (int i = 1; i < dataList.size(); i++) {
				int[] upData = dataList.get(i - 1);
				int[] data = dataList.get(i);
				
				copyArrays( maxSumCopy, maxSum );
				
				for (int j = 0; j < data.length;  j++) {
					int id = calculateMaxSum(j, upData, data[j], maxSumCopy, maxSum);
					markMax(j, id, traceStrCopy, traceStr);
				}
				traceStrCopy = copyStrs( traceStr);
			}
			
			
			for( int i =  0; i < lastDataLen; i ++){
				System.out.println( traceStr[i]);
			}
			
			int maxId = 0;
			int maxVal = 0;
			for( int i =  0; i < lastDataLen; i ++){
				if( maxSum[i] > maxVal){
					maxVal = maxSum[i];
					maxId = i;
				}
			}
			
			System.out.println("maxId=" + maxId + ", val=" + maxVal);

		}

		private static String[] copyStrs( String[] traceStr) {
			
			String []traceStrCopy = new String[ traceStr.length];
			for( int i =  0; i < traceStr.length ; i ++){
				traceStrCopy[i] = new String(traceStr[i]);
			}
			
			return  traceStrCopy;
			
		}

		private static void copyArrays(int[] maxSumCopy, int[] maxSum) {
			for( int i = 0 ; i < maxSum.length ; i ++){
				maxSumCopy[i] = maxSum[i];
			}
		}

		private static Direction markMax(int currentIndex, int upId, String[] traceStrCopy, String[] traceStr) {
			
			Direction dir = null;
			
			if (upId > currentIndex) {
				dir = Direction.DownLeft;
			} else if (upId == currentIndex) {
				dir = Direction.Down;
			} else {
				dir = Direction.DownRight;
			}
			
			traceStr[currentIndex] = traceStrCopy[upId] + directionStr(dir);
			
			return dir;
		}

		private static int calculateMaxSum(int jId, int[] upData, int val, int[] maxSumCopy, int [] maxSum) {

			int maxVal = 0;
			int maxId = 0;
			for (int i = Math.max(0, jId - 1); i <= Math.min(jId,
					upData.length + 1); i++) {
				if (val + maxSumCopy[i] > maxVal) {
					maxVal = val + maxSumCopy[i];
					maxId = i;
				}
			}
			maxSum[jId] = maxSumCopy[maxId] + val; 
			return maxId;
		}

	}

}
